package com.example.filemonitor.book.service.impl;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import co.elastic.clients.elasticsearch.core.*;
import co.elastic.clients.elasticsearch.core.search.Highlight;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.transport.endpoints.BooleanResponse;
import co.elastic.clients.util.ObjectBuilder;
import com.example.filemonitor.book.entity.Book;
import com.example.filemonitor.book.vo.SearchVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

@Component
@Slf4j
public class EsClient {

    @Value("${monitor.urlPrefix}")
    String urlPrefix;

    /**
     * 索引名称
     */
    public static final String BOOK_INDEX = "book";

    @Resource
    private ElasticsearchClient client;

    /**
     * 判断索引是否存在
     *
     * @return
     * @throws Exception
     */
    public Boolean isExistsIndex() throws IOException {
        BooleanResponse exists = client.indices().exists(o -> o.index(BOOK_INDEX));
        return exists.value();
    }

    /**
     * 通过id 查询数据
     *
     * @param id id
     * @return EsDTO
     * @throws IOException
     */
    public Book getById(String id) throws IOException {
        GetResponse<Book> response = client.get(g -> g
                        .index(BOOK_INDEX)
                        .id(id),
                Book.class
        );
        return response.source();
    }

    /**
     * 条件查询，不分页
     *
     * @param query
     * @return
     * @throws IOException
     */
    public List<Book> getList(Query query) throws IOException {
        List<Book> list = new ArrayList<>();
        SearchResponse<Book> response = client.search(s -> s
                        .index(BOOK_INDEX)
                        .query(query),
                Book.class
        );
        List<Hit<Book>> hits = response.hits().hits();
        for (Hit<Book> hit : hits) {
            list.add(hit.source());
        }
        return list;
    }

    /**
     * 分页查询
     *
     * @param query 查询参数
     * @param size  每页大小
     * @param from  第几页
     * @return
     * @throws IOException
     */
    public SearchVo getPage(Query query, int from, int size) {
        //高亮
        Highlight highlight = Highlight.of(h -> {
                    h.fields("title", hf -> hf.preTags("<font color='red'>").postTags("</font>"));
                    h.fields("attachment.content", hf -> hf.preTags("<font color='red'>").postTags("</font>"));
                    return h;
                }
        );
        List<Book> list = new ArrayList<>();
        SearchResponse<Book> response = null;
        Function<SearchRequest.Builder, ObjectBuilder<SearchRequest>> searchFunc = builder -> {
            builder.index(BOOK_INDEX)
                    .query(query)
                    .size(size)
                    .from(from)
                    .sort(so -> so.score(ss -> ss.order(SortOrder.Desc)))
                     //.sort(so -> so.field(v -> v.field("update_time").order(SortOrder.Desc)))
                    .highlight(highlight);
            return builder;
        };
        try {
            response = client.search(searchFunc, Book.class);
        } catch (Exception e) {
            log.error("es 查询出错：{}", e);
            return new SearchVo();

        }
        List<Hit<Book>> hits = response.hits().hits();
        for (Hit<Book> hit : hits) {
            Book book = hit.source();
            Map<String, List<String>> hitHighlight = hit.highlight();
            book.setHighlight(hitHighlight);
            if(!StringUtils.isEmpty(hitHighlight.get("title"))){

                book.setTitle(hitHighlight.get("title").get(0));
            }

            if(!StringUtils.isEmpty(hitHighlight.get("attachment.content"))){
                String content = hitHighlight.get("attachment.content")
                        .stream()
                        .reduce((u, v) -> u + "………" + v).orElse("");
                book.setContent(content);
            }
            book.setUrl(urlPrefix+book.getPath());
            list.add(book);
        }
        SearchVo esResDTO = new SearchVo();
        esResDTO.setContents(list);
        esResDTO.setTotal(response.hits().total().value());
        return esResDTO;
    }


    /**
     * 单个保存(修改id 一样就会修改)
     *
     * @param esDTO
     * @return
     * @throws IOException
     */
    public String save(Book esDTO) throws IOException {
        IndexRequest.Builder<Book> indexReqBuilder = new IndexRequest.Builder<>();
        indexReqBuilder.index(BOOK_INDEX);
        indexReqBuilder.id(esDTO.getId()  );
        indexReqBuilder.document(esDTO);
        IndexResponse response = client.index(indexReqBuilder.build());
        return response.id();
    }

    /**
     * 批量添加
     *
     * @param list
     * @throws IOException
     */
    public void bulkSave(List<Book> list) throws IOException {
        BulkRequest.Builder br = new BulkRequest.Builder();
        for (Book o : list) {
            br.operations(op -> op
                    .index(idx -> idx
                            .index(BOOK_INDEX)
                            .id(o.getId() + "")
                            .document(o)
                    )
            );
        }
        client.bulk(br.build());
    }

    /***
     * 通过id 删除
     * @param id
     * @throws IOException
     */
    public void removeById(Long id) throws IOException {
        DeleteRequest de = DeleteRequest.of(d -> d.index(BOOK_INDEX).id(id + ""));
        client.delete(de);
    }

    /***
     * 通过id 批量删除
     * @param ids
     * @throws IOException
     */
    public void removeById(List<Long> ids) throws IOException {
        BulkRequest.Builder br = new BulkRequest.Builder();
        // 将每一个product对象都放入builder中
        ids.stream()
                .forEach(id -> br
                        .operations(op -> op
                                .delete(d -> d
                                        .index(BOOK_INDEX)
                                        .id(id + ""))));
        client.bulk(br.build());
    }

    /**
     * 根据查询进行删除
     *
     * @param query
     * @throws IOException
     */
    public void delQuery(Query query) throws IOException {
        DeleteByQueryRequest de = DeleteByQueryRequest.of(d -> d.index(BOOK_INDEX).query(query));
        client.deleteByQuery(de);
    }
}
